<template>
  <div class="background-content">
    <div class="row">
      <el-row>
        <el-col :span="11">
          <el-select
            v-model="background.fillType"
            @change="changeBackgroundType"
          >
            <el-option
              v-for="item in BackgroundFillMode"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            ></el-option>
          </el-select>
        </el-col>
        <el-col :span="2"></el-col>

        <el-col :span="11" v-if="background.fillType === 0">
          <el-popover trigger="click" placement="bottom" :width="265">
            <template #reference>
              <ColorButton :color="background.color || '#fff'" />
            </template>
            <ColorPicker
              :modelValue="background.color"
              @update:modelValue="(color: string) => updateBackground({color: color, fill: color})"
            />
          </el-popover>
        </el-col>

        <el-col :span="11" v-else-if="background.fillType === 1">
          <el-select v-model="background.imageSize" @change="changeImageSize">
            <el-option
              v-for="item in BackgroundFillImageMode"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            ></el-option>
          </el-select>
        </el-col>

        <el-col :span="11" v-else-if="background.fillType === 2">
          <el-select
            v-model="background.gradientType"
            @change="changeGradientType"
          >
            <el-option
              v-for="item in BackgroundFillGradientMode"
              :key="item.id"
              :value="item.value"
              :label="item.name"
            ></el-option>
          </el-select>
        </el-col>

        <el-col :span="11" v-else-if="background.fillType === 3">
          <el-select v-model="gridColorMode" @change="changeGridColorMode">
            <el-option
              v-for="item in BackgroundFillGridMode"
              :key="item.id"
              :label="item.name"
              :value="item.value"
            ></el-option>
          </el-select>
        </el-col>

        <el-col :span="11" v-else-if="background.fillType === 4">
          <el-button
            class="full-row"
            @click="generateShadingBackgroundRandom"
            >{{ $t("style.randomShape") }}</el-button
          >
        </el-col>
      </el-row>
    </div>
    <!-- 图片填充 -->
    <div v-if="background.fillType === 1">
      <FileInput @change="(files: FileList) => uploadBackgroundImage(files)">
        <div class="background-image">
          <div
            class="content"
            :style="{ backgroundImage: `url(${background.imageURL})` }"
          >
            <IconPlus />
          </div>
        </div>
      </FileInput>
    </div>

    <!-- 渐变填充 -->
    <div v-if="background.fillType === 2">
      <div class="background-gradient-body">
        <div
          class="gradient-content"
          v-for="(item, nameIndex) in GradientColorLibs"
          :key="nameIndex"
          :value="item.name"
          @click.stop="changeGradientName(item.name)"
        >
          <GradientFill
            :name="item.name"
            :type="background.gradientType"
            :colors="item.colors"
          ></GradientFill>
        </div>
      </div>
      <el-row>
        <el-col :span="7" class="slider-name"
          >{{ $t("style.opacity") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="1"
            :step="0.01"
            v-model="gradientOpacity"
            @change="generateGradientBackground"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{ gradientOpacity }}</el-col>
      </el-row>
      <el-row v-if="background.gradientType === 'linear'">
        <el-col :span="7" class="slider-name"
          >{{ $t("style.gradientAngle") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="360"
            :step="1"
            v-model="gradientRotate"
            @change="generateGradientBackground"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{ gradientRotate }}</el-col>
      </el-row>
      <el-row class="mb-10" v-if="background.gradientType === 'linear'">
        <el-col :span="7" class="slider-name"
          >{{ $t("style.horizontalPosition") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="1"
            :step="0.01"
            v-model="gradientOffsetX"
            @change="generateGradientBackground"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{ gradientOffsetX }}</el-col>
      </el-row>
      <el-row class="mb-10" v-else>
        <el-col :span="7" class="slider-name"
          >{{ $t("style.verticalPosition") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="1"
            :step="0.01"
            v-model="gradientOffsetY"
            @change="generateGradientBackground"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{ gradientOffsetY }}</el-col>
      </el-row>
      <div class="row">
        <div
          v-for="(item, index) in background.gradientColor"
          :key="index"
          class="gradient-box"
        >
          <el-popover trigger="click" width="265">
            <template #reference>
              <ColorButton :color="item.color || '#fff'" />
            </template>
            <ColorPicker
              :modelValue="item.color"
              @update:modelValue="(color: string) => updateGradientBackground(index, color)"
            />
          </el-popover>
        </div>
      </div>
    </div>

    <!-- 网格填充 -->
    <div class="mb-10" v-if="background.fillType === 3">
      <el-row>
        <el-col :span="4" class="slider-name"
          >{{ $t("style.strength") }}：</el-col
        >
        <el-col :span="16">
          <el-slider
            class="common-slider"
            :min="0"
            :max="1"
            :step="0.01"
            v-model="gridStrengthRef"
            @change="changeGridStrength"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{ gridStrengthRef }}</el-col>
      </el-row>
      <el-row>
        <el-col :span="4" class="slider-name"
          >{{ $t("style.variance") }}：</el-col
        >
        <el-col :span="16">
          <el-slider
            class="common-slider"
            :min="0"
            :max="1"
            :step="0.01"
            v-model="gridVarianceRef"
            @change="changeGridVariance"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{ gridVarianceRef }}</el-col>
      </el-row>
      <el-row class="mb-10">
        <el-col :span="4" class="slider-name">{{ $t("style.size") }}：</el-col>
        <el-col :span="16">
          <el-slider
            class="common-slider"
            :min="0.1"
            :max="0.25"
            :step="0.01"
            v-model="gridSizeRef"
            @change="changeGridSize"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{ gridSizeRef }}</el-col>
      </el-row>
      <el-row class="mb-10">
        <el-button class="full-row" @click="generateGridBackgroundRandom">{{
          $t("style.randomGeneration")
        }}</el-button>
      </el-row>
      <el-row class="mb-10">
        <el-radio-group class="full-ratio" v-model="isGridLibData">
          <el-radio-button :label="true">{{
            $t("style.colorSelect")
          }}</el-radio-button>
          <el-radio-button :label="false">{{
            $t("style.customize")
          }}</el-radio-button>
        </el-radio-group>
      </el-row>
      <el-row>
        <el-button
          class="full-row"
          v-if="isGridLibData"
          @click="generateGridBackgroundRandColor"
        >
          <IconShuffleOne />
        </el-button>
        <el-button class="full-row" v-else @click="showGridColorSelf">
          <IconPlus />
        </el-button>
      </el-row>
      <div class="mt-10" v-if="isGridLibData">
        <div
          class="row color-contianer"
          v-for="(item, index) in GridColorLibs"
          :key="index"
        >
          <div
            v-for="color in item.color"
            :key="color"
            class="color-box"
            :style="{ backgroundColor: color }"
            @click="changeGridColor(item.color)"
          ></div>
        </div>
      </div>
      <div class="mt-10" v-else>
        <div
          :class="[item.length > 0 ? 'row' : '', 'color-contianer']"
          v-for="(item, index) in gridColorRecent"
          :key="index"
        >
          <div
            v-for="color in item"
            :key="color"
            class="color-box"
            :style="{ backgroundColor: color }"
            @click="changeGridColor(item)"
          ></div>
        </div>
      </div>
    </div>

    <!-- 底纹填充 -->
    <div class="mb-10" v-if="background.fillType === 4">
      <el-row>
        <el-col :span="7" class="slider-name"
          >{{ $t("style.graphScale") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="1"
            :max="shadingColorLib.maxScale"
            :step="1"
            v-model="shadingBackground.scale"
            @change="changeShadingZoom"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{
          shadingBackground.scale
        }}</el-col>
      </el-row>
      <el-row>
        <el-col :span="7" class="slider-name"
          >{{ $t("style.horizontalPosition") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="shadingColorLib.width * 2"
            :step="1"
            v-model="shadingBackground.moveLeft"
            @change="changeShadingHorizontal"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{
          shadingBackground.moveLeft
        }}</el-col>
      </el-row>
      <el-row>
        <el-col :span="7" class="slider-name"
          >{{ $t("style.verticalPosition") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="shadingColorLib.height"
            :step="1"
            v-model="shadingBackground.moveTop"
            @change="changeShadingVertical"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{
          shadingBackground.moveTop
        }}</el-col>
      </el-row>

      <el-row
        v-if="
          shadingColorLib.mode === 'stroke-join' ||
          shadingColorLib.mode === 'stroke'
        "
      >
        <el-col :span="7" class="slider-name"
          >{{ $t("style.lineThickness") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0.5"
            :max="shadingColorLib.maxStroke"
            :step="0.5"
            v-model="shadingBackground.stroke"
            @change="changeShadingStroke"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{
          shadingBackground.stroke
        }}</el-col>
      </el-row>

      <el-row v-if="shadingColorLib.maxSpacing[0] > 0">
        <el-col :span="7" class="slider-name"
          >{{ $t("style.verticalSpace") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="shadingColorLib.maxSpacing[0]"
            :step="0.5"
            v-model="shadingBackground.spacing[0]"
            @change="changeShadingHSpacing"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{
          shadingBackground.spacing[0]
        }}</el-col>
      </el-row>

      <el-row v-if="shadingColorLib.maxSpacing[1] > 0">
        <el-col :span="7" class="slider-name"
          >{{ $t("style.horizontalSpace") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="shadingColorLib.maxSpacing[1]"
            :step="0.5"
            v-model="shadingBackground.spacing[1]"
            @change="changeShadingVSpacing"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{
          shadingBackground.spacing[1]
        }}</el-col>
      </el-row>

      <el-row>
        <el-col :span="7" class="slider-name"
          >{{ $t("style.rotationAngle") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="0"
            :max="180"
            :step="1"
            v-model="shadingBackground.angle"
            @change="changeShadingAngle"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{
          shadingBackground.angle
        }}</el-col>
      </el-row>
      <el-row>
        <el-col :span="7" class="slider-name"
          >{{ $t("style.colorNumber") }}：</el-col
        >
        <el-col :span="13">
          <el-slider
            class="common-slider"
            :min="2"
            :max="shadingColorLib.colors"
            :step="1"
            v-model="shadingBackground.colorCounts"
            @change="changeShadingColors"
          />
        </el-col>
        <el-col :span="4" class="slider-num">{{
          shadingBackground.colorCounts
        }}</el-col>
      </el-row>
      <div class="row">
        <div
          v-for="(color, index) in shadingBackground.colors"
          :key="index"
          :class="
            index + 1 <= shadingBackground.colorCounts
              ? 'color-item'
              : 'color-non'
          "
          :style="{ backgroundColor: color }"
        >
          <el-popover trigger="click" placement="bottom" :width="265">
            <template #reference>
              <div class="color-select"></div>
            </template>
            <ColorPicker
              :modelValue="color"
              @update:modelValue="(color: string) => changeShadingIndexColor(index, color)"
            />
          </el-popover>
        </div>
      </div>
      <div class="background-shading-body">
        <div
          v-for="item in shadingColorLibs"
          :key="item.title"
          class="shading-box"
          :style="{
            backgroundImage: `url(&quot;${shadingSvgPattern(
              item.width,
              item.height,
              item.path,
              item.mode
            )}&quot;)`,
          }"
          @click="changeShadingElement(item)"
        >
          <!-- <span>{{item.title}}</span> -->
        </div>
      </div>
    </div>
    <GridFill
      v-model:visible="gridColorDialog"
      @close="hideGridColorSelf"
      @save="saveGridColorSelf"
    ></GridFill>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, watch, onMounted } from "vue";
import { useMainStore, useTemplatesStore } from "@/store";
import { storeToRefs } from "pinia";
import { debounce } from "lodash-es";
import { Gradient, Pattern, Image, util } from "fabric";
import {
  TransparentFill,
  BackgroundFillMode,
  BackgroundFillImageMode,
  BackgroundFillGridMode,
  BackgroundFillGradientMode,
} from "@/configs/background";
import { GridColorLibs } from "@/configs/colorGrid";
import { GradientColorLibs } from "@/configs/colorGradient";
import {
  ShadingLigntColors,
  ShadingColorLibInit,
  ShadingBackgroudInit,
} from "@/configs/colorShading";
import { GradientCoords } from "@/types/elements";
import { ShadingBackground, ShadingColorLib } from "@/types/elements";
import { WorkSpaceDrawType, propertiesToInclude } from "@/configs/canvas";
import { ImageElement, WorkSpaceElement } from "@/types/canvas";
import { getRandomNum } from "@/utils/common";
import { getImageDataURL } from "@/utils/image";
import { getColorShading } from "@/api/color";
import trianglify from "@/plugins/trianglify/trianglify";
import useCanvas from "@/views/Canvas/useCanvas";
import GridFill from "./GridFill.vue";
import GradientFill from "./GradientFill.vue";
import useHandleBackground from "@/hooks/useHandleBackground";

const templatesStore = useTemplatesStore();
const { setBackgroudImage } = useHandleBackground();
const { currentTemplate } = storeToRefs(templatesStore);

// 渐变偏移
const gradientOpacity = ref(1);
const gradientRotate = ref(0);
const gradientOffsetX = ref(0);
const gradientOffsetY = ref(0);

// 网格 预定义 参数
const RECENT_GRIDS = "RECENT_GRIDS";
const gridColorRecent = ref<[string[]]>([[]]);
const isGridLibData = ref(true);
const gridColorMode = ref<"interpolateLinear" | "sparkle" | "shadows">(
  "sparkle"
);
const gridSizeRef = ref(0.15);
const gridColorsRef = ref<string[]>(GridColorLibs[0].color);
const gridStrengthRef = ref(0.5);
const gridVarianceRef = ref(0.5);
const gridColorDialog = ref(false);

const shadingColorLibs = ref<ShadingColorLib[]>([]);
const shadingColorLib = ref<ShadingColorLib>(ShadingColorLibInit); // 底纹 预定义 参数
const shadingBackground = ref<ShadingBackground>(ShadingBackgroudInit);

// 加载缓存最近添加的网格
onMounted(async () => {
  const recentGridCache = localStorage.getItem(RECENT_GRIDS);
  if (recentGridCache) gridColorRecent.value = JSON.parse(recentGridCache);
  const res = await getColorShading();
  shadingColorLibs.value = res.data;
  shadingColorLib.value = shadingColorLibs.value[0];
});

const background = computed(() => {
  if (!currentTemplate.value) {
    return {
      fillType: 0,
      fill: TransparentFill,
      backgroundColor: "#fff",
    } as WorkSpaceElement;
  }
  if (!currentTemplate.value.workSpace) {
    return {
      fillType: 0,
      fill: TransparentFill,
      backgroundColor: "#fff",
    } as WorkSpaceElement;
  }
  return currentTemplate.value.workSpace;
});

// 设置背景图片隐藏
const removeBackgroundElement = () => {
  const [canvas] = useCanvas();
  canvas.set("backgroundImage", null);
  canvas.renderAll();
};

// 设置背景模式：纯色，图片，渐变，网格，形状，智能
const changeBackgroundType = (type: number) => {
  // 纯色
  if (type === 0) {
    const templateBackground: WorkSpaceElement = {
      ...background.value,
      fillType: type,
      fill: background.value.color || "#fff",
    };
    removeBackgroundElement();
    updateBackground(templateBackground);
  }
  // 图片
  else if (type === 1) {
    const templateBackground: WorkSpaceElement = {
      ...background.value,
      fillType: type,
      fill: "#fff",
      imageURL: background.value.imageURL || "",
      imageSize: background.value.imageSize || "cover",
    };
    removeBackgroundElement();
    updateBackground(templateBackground);
    if (background.value.imageURL) {
      changeBackgroundImage(background.value.imageURL);
    }
  }
  // 网格
  else if (type === 3) {
    const templateBackground: WorkSpaceElement = {
      ...background.value,
      fillType: type,
      backgroundColor: TransparentFill,
      gaidImageURL: background.value.gaidImageURL || "",
    };
    updateBackground(templateBackground);
    generateGridBackground();
  }
  // 底纹
  else if (type === 4) {
    const templateBackground: WorkSpaceElement = {
      ...background.value,
      fillType: type,
      backgroundColor: TransparentFill,
      shadingImageURL: background.value.shadingImageURL || "",
    };
    removeBackgroundElement();
    updateBackground(templateBackground);
    generateShadingBackground();
  }
  // 渐变
  else {
    const templateBackground: WorkSpaceElement = {
      ...background.value,
      fillType: 2,
      gradientType: background.value.gradientType || "linear",
      gradientColor:
        background.value.gradientColor || GradientColorLibs[0].colors,
      gradientName: background.value.gradientName || GradientColorLibs[0].name,
    };
    updateBackground(templateBackground);
    generateGradientBackground();
  }
};

// 设置背景
const updateBackground = (props: Partial<WorkSpaceElement>) => {
  const [canvas] = useCanvas();
  const workSpaceDraw = canvas.getObjects().filter((item) => item.id === WorkSpaceDrawType)[0];
  if (!workSpaceDraw) return;
  workSpaceDraw.set({ ...props });
  if (props.fill instanceof Pattern) {
    props.fill = props.fill.toObject() as Pattern
  }
  templatesStore.updateWorkSpace({ workSpace: { ...background.value, ...props }});
  const workProps = workSpaceDraw.toObject(propertiesToInclude as any[]);
  templatesStore.updateElement({ id: workSpaceDraw.id, props: { ...workProps, ...props }});
  canvas.renderAll();
};

// 修改上传背景
const changeBackgroundImage = async (imageURL: string) => {
  if (background.value.imageSize === "repeat") {
    const backgroundImage = await util.loadImage(imageURL);
    const workSpacePattern = new Pattern({
      source: backgroundImage,
      repeat: "repeat",
    });
    updateBackground({ fill: workSpacePattern, imageURL });
  } else {
    setBackgroudImage(imageURL);
    updateBackground({ fill: TransparentFill, imageURL });
  }
};

// 上传背景图片
const uploadBackgroundImage = (files: FileList) => {
  const imageFile = files[0];
  if (!imageFile) return;
  getImageDataURL(imageFile).then((imageURL) => {
    changeBackgroundImage(imageURL);
  });
};

// 修改背景图片
const changeImageSize = () => {
  if (!background.value.imageURL) return;
  changeBackgroundImage(background.value.imageURL);
};

// 修改渐变名字
const changeGradientName = (gradientName: string) => {
  const gradientColorLib = GradientColorLibs.filter(
    (item) => item.name === gradientName
  )[0];
  if (gradientColorLib) {
    background.value.gradientName = gradientName;
    updateBackground({ gradientColor: gradientColorLib.colors });
    generateGradientBackground();
  }
};

// 修改渐变类型
const changeGradientType = () => {
  updateBackground({ gradientType: background.value.gradientType });
  generateGradientBackground();
};

// 修改渐变颜色
const updateGradientBackground = (index: number, color: string) => {
  const gradientBackgroundColor = background.value.gradientColor;
  if (gradientBackgroundColor) {
    gradientBackgroundColor[index].color = color;
    updateBackground({ gradientColor: gradientBackgroundColor });
    generateGradientBackground();
  }
};

// 生成渐变背景
const generateGradientBackground = () => {
  const [canvas] = useCanvas();
  const workSpaceDraw = canvas
    .getObjects()
    .filter((item) => item.id === WorkSpaceDrawType)[0];
  if (!workSpaceDraw) return;
  const width = workSpaceDraw.width;
  const height = workSpaceDraw.height;
  if (!width || !height) return;
  let coords: GradientCoords = { x1: 0, y1: 0, x2: width, y2: 0 };
  if (background.value.gradientType !== "linear") {
    coords = {
      r1: 0,
      r2: height / 2,
      x1: width / 2,
      y1: height / 2,
      x2: width / 2,
      y2: height / 2,
    };
  }
  const rotateCos = Math.cos((gradientRotate.value * Math.PI) / 180.0);
  const rotateSin = Math.sin((gradientRotate.value * Math.PI) / 180.0);
  const gradient = new Gradient({
    type: background.value.gradientType,
    colorStops: background.value.gradientColor || GradientColorLibs[0].colors,
    coords: coords,
    offsetX: gradientOffsetX.value * width,
    offsetY: gradientOffsetY.value * height,
    gradientTransform: [rotateCos, rotateSin, -1 * rotateSin, rotateCos, 0, 0],
  });
  updateBackground({ fill: gradient, opacity: gradientOpacity.value });
};

// 更新缓存保存最大的网格
const updateGridColorRecentCache = debounce(
  function () {
    const maxLength = 10;
    if (gridColorRecent.value.length > maxLength) {
      gridColorRecent.value = gridColorRecent.value.slice(0, maxLength) as [
        string[]
      ];
    }
  },
  300,
  { trailing: true }
);

// 保存缓存最近添加的网格
watch(
  gridColorRecent,
  () => {
    const recentGridCache = JSON.stringify(gridColorRecent.value);
    localStorage.setItem(RECENT_GRIDS, recentGridCache);
  },
  { deep: true }
);

// 修改网格图片强度
const changeGridStrength = (value: number) => {
  gridStrengthRef.value = value;
  generateGridBackground();
};
// 修改网格图片方差
const changeGridVariance = (value: number) => {
  gridVarianceRef.value = value;
  generateGridBackground();
};
// 修改网格图片尺寸
const changeGridSize = (value: number) => {
  gridSizeRef.value = value;
  generateGridBackground();
};

// 随机数字生成网格
const generateGridBackgroundRandom = () => {
  gridStrengthRef.value = Math.floor(getRandomNum(0, 1) * 100) / 100;
  gridVarianceRef.value = Math.floor(getRandomNum(0, 1) * 100) / 100;
  gridSizeRef.value = Math.floor(getRandomNum(0, 0.25) * 100) / 100;
  generateGridBackground();
};

// 随机颜色生成网格
const generateGridBackgroundRandColor = () => {
  generateGridBackground("random");
};

// 显示网格自定义
const showGridColorSelf = () => {
  gridColorDialog.value = true;
};
// 隐藏网格自定义
const hideGridColorSelf = () => {
  gridColorDialog.value = false;
};

// 保存网格自定义
const saveGridColorSelf = (colors: string[]) => {
  gridColorRecent.value.unshift(colors);
  updateGridColorRecentCache();
};

// 选择网格图片色彩
const changeGridColor = (colors: string[]) => {
  gridColorsRef.value = colors;
  generateGridBackground();
};

const changeGridColorMode = (
  mode: "interpolateLinear" | "sparkle" | "shadows"
) => {
  gridColorMode.value = mode;
  generateGridBackground();
};

// 获取网格图片颜色模式
const getGridColorFunction = () => {
  if (gridColorMode.value === "interpolateLinear") {
    return trianglify.colorFunctions.interpolateLinear(gridStrengthRef.value);
  } else if (gridColorMode.value === "sparkle") {
    return trianglify.colorFunctions.sparkle(gridStrengthRef.value);
  } else if (gridColorMode.value === "shadows") {
    return trianglify.colorFunctions.shadows(gridStrengthRef.value);
  }
  return trianglify.colorFunctions.sparkle(gridStrengthRef.value);
};

// 生成网格图片
const generateGridBackground = async (status?: string) => {
  const [canvas] = useCanvas();
  const workSpaceDraw = canvas
    .getObjects()
    .filter((item) => item.id === WorkSpaceDrawType)[0];
  if (!workSpaceDraw || !workSpaceDraw.width) return;
  const gridColors =
    gridColorsRef.value && gridColorsRef.value.length > 0 && status !== "random"
      ? gridColorsRef.value
      : "random";
  const defaultOptions = {
    width: workSpaceDraw.width,
    height: workSpaceDraw.height,
    cellSize: gridSizeRef.value * workSpaceDraw.width,
    variance: gridVarianceRef.value,
    seed: null,
    xColors: gridColors,
    yColors: "match",
    fill: true,
    palette: trianglify.utils.colorbrewer,
    colorSpace: "lab",
    colorFunction: getGridColorFunction(),
    strokeWidth: 0,
    points: null,
  };
  const trianglifier = trianglify(defaultOptions);
  const canvasBackground = trianglifier.toSVG(undefined, undefined);
  const serialize = new XMLSerializer();
  const imageURL = `data:image/svg+xml;base64,${btoa(serialize.serializeToString(canvasBackground))}`;
  const backgroundImage = await Image.fromURL(imageURL, {crossOrigin: "anonymous"}, {
    left: workSpaceDraw.left,
    top: workSpaceDraw.top,
    angle: workSpaceDraw.angle,
    scaleX: workSpaceDraw.scaleX,
    scaleY: workSpaceDraw.scaleY,
    width: workSpaceDraw.width,
    height: workSpaceDraw.height,
  });
  canvas.set("backgroundImage", backgroundImage);
  templatesStore.setBackgroundImage(backgroundImage.toObject());
  updateBackground({ fill: TransparentFill, gaidImageURL: imageURL });
};

// 底纹样式读取
const shadingSvgPattern = (
  width: number,
  height: number,
  path: string,
  mode: string
) => {
  let strokeGroup = "";
  for (let i = 0; i < path.split("~").length; i++) {
    const svgColor = ShadingLigntColors[i + 1];
    let strokeFill = `stroke-width='1' stroke='${svgColor}' fill='none'`;
    if (mode === "fill") strokeFill = `stroke='none' fill='${svgColor}'`;
    strokeGroup += path.split("~")[i].replace("/>", ` ${strokeFill}/>`);
  }
  const patternData =
    "<svg width='100%' height='100%' xmlns='http://www.w3.org/2000/svg'><defs>" +
    "<pattern id='a' patternUnits='userSpaceOnUse' width='" +
    width +
    "' height='" +
    height +
    "'><rect x='0' y='0' width='" +
    width +
    "' height='" +
    height +
    "' fill='" +
    ShadingLigntColors[0] +
    "'/>" +
    strokeGroup +
    "</pattern></defs><rect width='100%' height='100%' fill='url(%23a)'/></svg>";
  const svgShading = `data:image/svg+xml;base64,${btoa(patternData)}`;
  return svgShading;
};

// 多笔画底纹
const multiStroke = (
  index: number,
  vHeight: number,
  maxColors: number,
  mode: string,
  path: string,
  item: ShadingBackground
) => {
  const colors = item.colors;
  const colorCounts = item.colorCounts;
  const join = item.join;
  const spacing = item.spacing;
  const stroke = item.stroke;
  let defColor = colors[index + 1];
  let strokeFill = "",
    joinMode = "";
  if (vHeight === 0 && maxColors > 2) {
    if (colorCounts === 3 && maxColors === 4 && index === 2)
      defColor = colors[1];
    else if (colorCounts === 4 && maxColors === 5 && index === 3)
      defColor = colors[1];
    else if (colorCounts === 3 && maxColors === 5 && index === 3)
      defColor = colors[1];
    else if (colorCounts === 3 && maxColors === 5 && index === 2)
      defColor = colors[1];
    else if (colorCounts === 2) defColor = colors[1];
  }
  if (mode === "stroke-join") {
    strokeFill = " stroke='" + defColor + "' fill='none'";
    joinMode =
      join === 2
        ? "stroke-linejoin='round' stroke-linecap='round' "
        : "stroke-linecap='square' ";
  } else if (mode === "stroke") {
    strokeFill = " stroke='" + defColor + "' fill='none'";
  } else {
    strokeFill = " stroke='none' fill='" + defColor + "'";
  }
  return path
    .split("~")
    [index].replace(
      "/>",
      " transform='translate(" +
        spacing[0] / 2 +
        ",0)' " +
        joinMode +
        "stroke-width='" +
        stroke +
        "'" +
        strokeFill +
        "/>"
    )
    .replace("transform='translate(0,0)' ", " ");
};

// 底纹样式背景生成
const generateShadingBackground = async () => {
  const [canvas] = useCanvas();
  const workSpaceDraw = canvas
    .getObjects()
    .filter((item) => item.id === WorkSpaceDrawType)[0];
  if (!workSpaceDraw) return;
  const item = shadingColorLib.value;
  const maxColors = item.path.split("~").length + 1;
  const width = item.width;
  const height = item.height;
  const vHeight = item.vHeight;
  const path = item.path;
  const mode = item.mode;
  const svgWidth = width + shadingBackground.value.spacing[0];
  const svgHeight =
    height -
    vHeight * (maxColors - shadingBackground.value.colorCounts) +
    shadingBackground.value.spacing[1];
  const imageWidth = workSpaceDraw.width,
    imageHeight = workSpaceDraw.height;
  let strokeGroup = "";
  for (let i = 0; i < maxColors - 1; i++) {
    strokeGroup += multiStroke(
      i,
      vHeight,
      maxColors,
      mode,
      path,
      shadingBackground.value
    );
  }
  const translateX =
    shadingBackground.value.scale * shadingBackground.value.moveLeft;
  const translateY =
    shadingBackground.value.scale * shadingBackground.value.moveTop;
  const svg = `
    <svg id='patternId' width='${imageWidth}' height='${imageHeight}' xmlns='http://www.w3.org/2000/svg'>
      <defs>
        <pattern id='a' patternUnits='userSpaceOnUse' 
          width='${svgWidth}' 
          height='${svgHeight}'
          patternTransform='scale(${shadingBackground.value.scale}) rotate(${shadingBackground.value.angle})'
        >
          <rect x='0' y='0' width='100%' height='100%' fill='${shadingBackground.value.colors[0]}'/>
          ${strokeGroup}
        </pattern>
      </defs>
      <rect x="0" y="0" width='${imageWidth}' height='${imageHeight}' transform='translate(${translateX},${translateY})' fill='url(%23a)' />
    </svg>
  `;
  const imageURL = `data:image/svg+xml;base64,${btoa(svg)}`;
  const backgroundImage = await Image.fromURL(imageURL, {crossOrigin: "anonymous"}, {});
  const left = workSpaceDraw.left,
    top = workSpaceDraw.top,
    angle = workSpaceDraw.angle,
    scaleX = workSpaceDraw.scaleX,
    scaleY = workSpaceDraw.scaleY;
  backgroundImage.set({
    left,
    top,
    angle,
    scaleX,
    scaleY,
    width: imageWidth,
    height: imageHeight,
  });

  canvas.set("backgroundImage", backgroundImage);
  updateBackground({ shadingImageURL: imageURL, fill: TransparentFill });
  templatesStore.setBackgroundImage(backgroundImage.toObject());
};

// // 选择底纹填充
const changeShadingElement = (item: ShadingColorLib) => {
  shadingColorLib.value = item;
  shadingBackground.value.colorCounts = item.colors;
  generateShadingBackground();
};

// 修改底纹缩放
const changeShadingZoom = (value: number) => {
  shadingBackground.value.scale = value;
  generateShadingBackground();
};
// 修改底纹水平位置
const changeShadingHorizontal = (value: number) => {
  shadingBackground.value.moveLeft = value;
  generateShadingBackground();
};
// 修改底纹垂直位置
const changeShadingVertical = (value: number) => {
  shadingBackground.value.moveTop = value;
  generateShadingBackground();
};
// 修改底纹线条粗细
const changeShadingStroke = (value: number) => {
  shadingBackground.value.stroke = value;
  generateShadingBackground();
};
// 修改底纹水平间隔
const changeShadingHSpacing = (value: number) => {
  shadingBackground.value.spacing[0] = value;
  generateShadingBackground();
};
// 修改底纹垂直间隔
const changeShadingVSpacing = (value: number) => {
  shadingBackground.value.spacing[1] = value;
  generateShadingBackground();
};
// 修改底纹填充旋转角度
const changeShadingAngle = (value: number) => {
  shadingBackground.value.angle = value;
  generateShadingBackground();
};
// 修改底纹填充颜色数量
const changeShadingColors = (value: number) => {
  shadingBackground.value.colorCounts = value;
  generateShadingBackground();
};

// 修改底纹填充颜色
const changeShadingIndexColor = (index: number, color: string) => {
  // shadingBackground.value.colors[index] = color
  generateShadingBackground();
};

// 随机底纹填充形状
const generateShadingBackgroundRandom = () => {
  const item =
    shadingColorLibs.value[
      Math.floor(getRandomNum(0, shadingColorLibs.value.length - 1))
    ];
  shadingColorLib.value = item;
  if (item.colors) shadingBackground.value.colorCounts = item.colors;
  generateShadingBackground();
};

// 设置背景图片
// const generateBackgroundImage = async (backgroundImage: Image, url: string) => {
//   const [ canvas ] = useCanvas()
//   canvas.set('backgroundImage', backgroundImage)
//   // if (canvasObject.value && canvasObject.value.name === 'backgroundImage') {
//   //   const imageElement = canvasObject.value as Image
//   //   await imageElement.setSrc(url)
//   // }
//   // else {
//   //   canvas.backgroundImage = backgroundImage
//   // }
// }
</script>

<style lang="scss" scoped>
.icon-btn {
  cursor: pointer;
}
.canvas-design-panel {
  user-select: none;
}
.row {
  width: 100%;
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}
.title {
  margin-bottom: 10px;
}

.fixed-ratio {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.slider-name {
  display: flex;
  align-items: center;
}
.slider-num {
  display: flex;
  align-items: center;
  justify-content: center;
}
.mb-10 {
  margin-bottom: 10px;
}
.full-row {
  flex: 1;
  width: 100%;
}

.full-group {
  display: flex;
  flex: 1;
  .el-button {
    width: 50%;
  }
}

.full-ratio {
  display: flex;
  flex: 1;
  .el-radio-button {
    width: 50%;
  }
  .el-radio-button__inner {
    width: 100%;
  }
}

.background-image {
  height: 0;
  padding-bottom: 56.25%;
  border: 1px dashed var(--el-border-color);
  border-radius: $borderRadius;
  position: relative;
  transition: all $transitionDelay;

  &:hover {
    border-color: var(--el-color-primary);
    color: var(--el-color-primary);
  }

  .content {
    @include absolute-0();

    display: flex;
    justify-content: center;
    align-items: center;
    background-position: center;
    background-size: contain;
    background-repeat: no-repeat;
    cursor: pointer;
  }
}

.theme-list {
  @include flex-grid-layout();
}
.theme-item {
  @include flex-grid-layout-children(2, 48%);

  padding-bottom: 30%;
  border-radius: $borderRadius;
  position: relative;
  cursor: pointer;

  .theme-item-content {
    @include absolute-0();

    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 8px;
    border: 1px solid $borderColor;
  }

  .text {
    font-size: 16px;
  }
  .colors {
    display: flex;
  }
  .color-block {
    margin-top: 8px;
    width: 12px;
    height: 12px;
    margin-right: 2px;
  }
  &:hover .btns {
    display: flex;
  }

  .btns {
    @include absolute-0();

    flex-direction: column;
    justify-content: center;
    align-items: center;
    display: none;
    background-color: rgba($color: #000, $alpha: 0.25);
  }
  .btn {
    width: 72px;
    padding: 5px 0;
    text-align: center;
    background-color: $themeColor;
    color: #fff;
    font-size: 12px;
    border-radius: $borderRadius;

    &:hover {
      background-color: #c42f19;
    }

    & + .btn {
      margin-top: 5px;
    }
  }
}
.slider {
  flex: 3;
}
.mt-10 {
  margin-top: 10px;
}
.color-group {
  display: flex;
  flex: 1 1;
}
.color-box {
  flex: 1 1;
  height: 25px;
}
.color-contianer:hover {
  box-shadow: 0 0 20px 2px rgb(0 0 0 / 40%);
  width: calc(100% - 5px) !important;
  cursor: pointer;
}

.config-strength {
  flex: 10;
}

.config-variance {
  flex: 10;
}
.config-size {
  flex: 10;
}
.gradient-box {
  display: flex;
  flex: 1;
  .el-button {
    width: 100%;
  }
}
.background-gradient-body {
  height: 300px;
  overflow: auto;
}
.gradient-content {
  display: flex;
  justify-content: center;
  padding-bottom: 2px;
}
.gradient-content:hover {
  width: calc(100% - 2px) !important;
  border-color: $themeColor;
  cursor: pointer;
}
.background-shading-body {
  height: 500px;
  overflow: auto;
}
.shading-box {
  flex: 1;
  height: 50px;
  margin-bottom: 5px;
  border: 1px solid transparent;
  border-color: #d9d9d9;
  border-radius: 5px;
}
.shading-box:hover {
  // box-shadow: 0 0 20px 2px rgb(0 0 0 / 40%);
  width: calc(100% - 2px) !important;
  cursor: pointer;
  border-color: $themeColor;
}
.color-item {
  height: 42px;
  border: 1px solid transparent;
  border-color: #d9d9d9;
  border-radius: 5px;
  flex: 1;
  display: inline-block;
  cursor: pointer;
  margin: 0 2px;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.color-item:hover {
  border-color: $themeColor;
}

.color-non {
  display: none;
}
.color-select {
  width: 100%;
  height: 100%;
}

.common-slider {
  width: 90%;
  margin: 0 auto;
}
</style>

<style scoped>
:deep(.el-input .el-input-group__prepend) {
  padding: 0 5px;
}
:deep(.el-input .el-input-group__append) {
  padding: 0 5px;
}
:deep(.full-ratio .el-radio-button__inner) {
  width: 100%;
}
</style>